package com.kylin.system.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kylin.common.core.exception.CheckException;
import com.kylin.common.core.service.impl.TreeServiceImpl;
import com.kylin.common.security.util.SecurityUtils;
import com.kylin.system.common.utils.Constants;
import com.kylin.system.entity.SysMenu;
import com.kylin.system.entity.SysUser;
import com.kylin.system.mapper.SysMenuMapper;
import com.kylin.system.mapper.SysRoleMenuMapper;
import com.kylin.system.model.Meta;
import com.kylin.system.model.Router;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 系统菜单服务层
 *
 * @author wuhao
 * @version 1.0 - 2021-03-29
 */
@Service
public class SysMenuService extends TreeServiceImpl<SysMenuMapper, SysMenu> {

    @Resource
    private SysRoleMenuMapper roleMenuMapper;




    /**
     * 根据用户查询系统菜单列表
     *
     * @param userId 用户ID
     * @return 菜单列表
     */
    public List<SysMenu> selectMenuList(Long userId)
    {
        return selectMenuList(new SysMenu(), userId);
    }

    /**
     * 查询系统菜单列表
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    public List<SysMenu> selectMenuList(SysMenu menu, Long userId)
    {
        List<SysMenu> menuList = null;
        // 管理员显示所有菜单信息
        if (SysUser.isAdmin(userId))
        {
            QueryWrapper<SysMenu> where = new QueryWrapper<>();
            where.like(StringUtils.isNotEmpty(menu.getMenuName()), "menu_name", menu.getMenuName())
                    .eq(ObjectUtils.isNotEmpty(menu.getHideInMenu()), "hide_in_menu", menu.getHideInMenu())
                    .eq(StringUtils.isNotBlank(menu.getStatus()),"status", menu.getStatus())
                    .eq(StringUtils.isNotBlank(menu.getMenuType()), "menu_type", menu.getMenuType());
            menuList = mapper.selectList(where);
        }
        else
        {
            menuList = mapper.selectMenuListByUserId(menu.getMenuType(),menu.getMenuName(), menu.getHideInMenu(), menu.getStatus(), userId);
        }
        return menuList;
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    public Set<String> selectMenuPermsByUserId(Long userId)
    {
        List<String> perms = mapper.selectMenuPermsByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms)
        {
            if (StringUtils.isNotEmpty(perm))
            {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;
    }

    /**
     * 根据用户ID查询菜单
     *
     * @param userId 用户名称
     * @return 菜单列表
     */
    public List<SysMenu> selectMenuTreeByUserId(Long userId)
    {
        List<SysMenu> menus = null;
        if (SecurityUtils.isAdmin(userId))
        {
            menus = mapper.selectMenuTreeAll();
        }
        else
        {
            menus = mapper.selectMenuTreeByUserId(userId);
        }
        return getChildPerms(menus, 0);
    }

    /**
     * 根据角色ID查询菜单树信息
     *
     * @param roleId 角色ID
     * @return 选中菜单列表
     */
    public List<Long> selectMenuListByRoleId(Long roleId)
    {
        return mapper.selectMenuListByRoleId(roleId);
    }

    /**
     * 构建前端路由所需要的菜单
     *
     * @param menus 菜单列表
     * @return 路由列表
     */
    public List<Router> buildMenus(List<SysMenu> menus)
    {
        List<Router> routers = new LinkedList<>();
        for (SysMenu menu : menus)
        {
            Router router = new Router();
//            router.setHidden("1".equals(menu.getVisible()));
            router.setName(menu.getRouteName());
//            router.setPath(getRouterPath(menu));
            router.setPath(menu.getRoutePath());
            router.setComponent(menu.getComponent());
            Meta meta = new Meta(menu.getMenuName(), menu.getIcon());
            meta.setOrder(menu.getTreeSort());
            meta.setHideInMenu(menu.getHideInMenu());
            meta.setActiveMenu(menu.getActiveMenu());
            router.setMeta(meta);
            List<SysMenu> cMenus = menu.getChildren();
            if (!cMenus.isEmpty() && Constants.TYPE_DIR.equals(menu.getMenuType()))
            {
//                router.setAlwaysShow(true);
//                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            }
//            else if (isMeunFrame(menu))
//            {
//                List<Router> childrenList = new ArrayList<>();
//                Router children = new Router();
//                children.setPath(menu.getRoutePath());
//                children.setComponent(menu.getComponent());
//                children.setName(menu.getRoutePath());
//                children.setMeta(new Meta(menu.getMenuName(), menu.getIcon(), menu.getTreeSort(), menu.getI18nKey()));
//                childrenList.add(children);
//                router.setChildren(childrenList);
//            }
            routers.add(router);
        }
        return routers;
    }


    /**
     * 构建前端路由所需要的菜单 for react
     *
     * @param menus 菜单列表
     * @return 路由列表
     */
    public List<Router> buildMenusForReact(List<SysMenu> menus)
    {
        List<Router> routers = new LinkedList<>();
        for (SysMenu menu : menus)
        {
            Router router = new Router();
//            router.setHidden("1".equals(menu.getVisible()));
            router.setName(getRouteName(menu));
            router.setPath(menu.getRoutePath());
            // 添加react需要的菜单值 add by wuhao at 20240425
//            router.setTitle(menu.getMenuName());
//            router.setIcon(menu.getIcon());
            // 添加react需要的菜单值 end
            router.setComponent(getComponent(menu));
            router.setMeta(new Meta(menu.getMenuName(), menu.getIcon()));
            List<SysMenu> cMenus = menu.getChildren();
            if (!cMenus.isEmpty() && Constants.TYPE_DIR.equals(menu.getMenuType()))
            {
//                router.setAlwaysShow(true);
//                router.setRedirect("noRedirect");
                router.setChildren(buildMenusForReact(cMenus));
            }
            else if (isMeunFrame(menu))
            {
                List<Router> childrenList = new ArrayList<>();
                Router children = new Router();
                children.setPath(menu.getRoutePath());
                children.setComponent(menu.getComponent());
                children.setName(menu.getRoutePath());
                children.setMeta(new Meta(menu.getMenuName(), menu.getIcon()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }



    /**
     * 查询菜单是否被角色绑定
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean checkMenuExistRole(Long menuId)
    {
        int result = roleMenuMapper.checkMenuExistRole(menuId);
        return result > 0 ;
    }


    /**
     * 校验菜单名称是否唯一
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public void checkMenuNameUnique(SysMenu menu)
    {
        Long menuId = ObjectUtils.isEmpty(menu.getId()) ? -1L : menu.getId();
        QueryWrapper<SysMenu> where = new QueryWrapper<>();
        where.eq("menu_name", menu.getMenuName()).eq("parent_id", menu.getParentId());
        SysMenu info = mapper.selectOne(where);
        if (ObjectUtils.isNotEmpty(info) && info.getId().longValue() != menuId.longValue())
        {
            throw new CheckException("菜单名称已存在");
        }
    }

    /**
     * 获取路由名称
     *
     * @param menu 菜单信息
     * @return 路由名称
     */
    public String getRouteName(SysMenu menu)
    {
        String routerName = StringUtils.capitalize(menu.getRoutePath());
        // 非外链并且是一级目录（类型为目录）
        if (isMeunFrame(menu))
        {
            routerName = StringUtils.EMPTY;
        }
        return routerName;
    }

    /**
     * 获取路由地址
     *
     * @param menu 菜单信息
     * @return 路由地址
     */
    public String getRouterPath(SysMenu menu)
    {
        String routerPath = menu.getRoutePath();
        // 非外链并且是一级目录（类型为目录）
        if (0 == menu.getParentId() && Constants.TYPE_DIR.equals(menu.getMenuType())
                && Constants.NO_FRAME.equals(menu.getIsFrame()))
        {
            routerPath = String.format("/%s", menu.getRoutePath());
        }
        // 非外链并且是一级目录（类型为菜单）
        else if (isMeunFrame(menu))
        {
            routerPath = "/";
        }
        return routerPath;
    }

    /**
     * 获取组件信息
     *
     * @param menu 菜单信息
     * @return 组件信息
     */
    public String getComponent(SysMenu menu)
    {
        String component = Constants.LAYOUT;
        if (StringUtils.isNotEmpty(menu.getComponent()) && !isMeunFrame(menu))
        {
            component = menu.getComponent();
        }
        return component;
    }

    /**
     * 是否为菜单内部跳转
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isMeunFrame(SysMenu menu)
    {
        return menu.getParentId() == 0 && Constants.TYPE_MENU.equals(menu.getMenuType())
                && menu.getIsFrame().equals(Constants.NO_FRAME);
    }

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list 分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId)
    {
        List<SysMenu> returnList = new ArrayList<>();
        for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)
        {
            SysMenu t = iterator.next();
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == parentId)
            {
                recursionFn(list, t);
                returnList.add(t);
            }
        }
        return returnList;
    }

    /**
     * 递归列表
     *
     * @param list
     * @param t
     */
    private void recursionFn(List<SysMenu> list, SysMenu t)
    {
        // 得到子节点列表
        List<SysMenu> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysMenu tChild : childList)
        {
            if (hasChild(list, tChild))
            {
                // 判断是否有子节点
                Iterator<SysMenu> it = childList.iterator();
                while (it.hasNext())
                {
                    SysMenu n = it.next();
                    recursionFn(list, n);
                }
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t)
    {
        List<SysMenu> tlist = new ArrayList<>();
        Iterator<SysMenu> it = list.iterator();
        while (it.hasNext())
        {
            SysMenu n = it.next();
            if (n.getParentId().equals(t.getId()))
            {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysMenu> list, SysMenu t)
    {
        return getChildList(list, t).isEmpty();
    }

}
